﻿namespace Rgr

type Figure() =
    let mutable internalSeq = seq []
    let mutable topP = new Point(-1, 32000);
    let mutable bottomP = new Point(-1,-2);
    let mutable leftP = new Point(32000,-1);
    let mutable rightP = new Point(-1,-1);
    let mutable p1 = new Point(-1,-2);
    let mutable p2 = new Point(32000,-1);
    let mutable p3 = new Point(-1,-1);

    
    member this.Points
        with get() = internalSeq
        and set(value) = internalSeq <- value
    member this.AddPoint(p:Point) =
        let newPoint = new Point(p.X, p.Y);
        let internalSeqTest = Seq.append this.Points [newPoint];
        this.Points <- internalSeqTest
        
    member this.CheckRelationship(p:Point) = 
        let checkPoint p1 p2 =  Point.Equals(p1, p2);
        try
            let result = Seq.find( checkPoint p ) this.Points;
            true
        with
              | :? System.Collections.Generic.KeyNotFoundException -> false
        
    member this.PointHaveTwoNeighbor(p:Point) = 
        let checkPoint p1 p2 =  Point.Equals(p1, p2); 
        let neighborCount = ref 0;    
        Seq.iteri(fun y c ->  
            if not(p.Equals(c))
            then
                if checkPoint p c
                then 
                    neighborCount := !neighborCount + 1
            ) this.Points;
        !neighborCount >= 2 //точка сама себе сосед

    member this.CheckZamknut() = 
        let isZam = ref 0;        
        Seq.iteri(fun y c ->  
                if not ( this.PointHaveTwoNeighbor c )
                then 
                    isZam := 1
            ) this.Points;
            !isZam = 0

    member this.printPoints() =
        Seq.iteri(fun y c ->  
             printfn "point is %A at pos %d" c y        
        ) this.Points; 

    member this.findTopPoints()=
        let topPP = ref topP;
        let bottomPP = ref bottomP;
        let leftPP = ref leftP;
        let rightPP = ref rightP;
                
        Seq.iter(fun (p:Point) ->  
            if p.X >= rightPP.contents.X
            then
                rightPP := p;  
            if p.X <= leftPP.contents.X
            then
                leftPP := p;  
            if p.Y <= topPP.contents.Y
            then
                topPP := p;  
            if p.Y >= bottomPP.contents.Y
            then
                bottomPP := p;

            ) this.Points;

        rightP <- rightPP.contents;
        leftP <- leftPP.contents;
        bottomP <- bottomPP.contents;
        topP <- topPP.contents;
        
        if topP.Y = leftP.Y
        then topP <- new Point(leftP.X, topP.Y);
        if topP.Y = rightP.Y
        then topP <- new Point(rightP.X, topP.Y);
        if bottomP.Y = leftP.Y
        then bottomP <- new Point(leftP.X, bottomP.Y);
        if bottomP.Y = rightP.Y
        then bottomP <- new Point(rightP.X, bottomP.Y);

        p1 <- topP;
        p2 <- bottomP;
        if (Point.AbsoluteEq(p1, leftP) || Point.AbsoluteEq(p2, leftP))
        then p3 <- rightP
        else p3 <- leftP
    
    member this.doCircle() =
        //this.Points <- seq [];

        let mutable point1 = p1;
        let mutable point2 = p2;
        let mutable point3 = p3;
        if p1.X = p2.X
        then 
            point2 <- p3;
            point3 <- p2;
        if p3.X = p2.X
        then 
            point1 <- p2;
            point2 <- p1;
        let mutable ma = System.Convert.ToDouble(point2.Y - point1.Y) / System.Convert.ToDouble(point2.X - point1.X);
        let mutable mb = System.Convert.ToDouble(point3.Y - point2.Y) / System.Convert.ToDouble(point3.X - point2.X);
        let mutable x0 = (ma*mb*System.Convert.ToDouble(point1.Y-point3.Y)+mb*System.Convert.ToDouble(point1.X+point2.X)-ma*System.Convert.ToDouble(point2.X+point3.X))/(2.0*(mb-ma));
        let mutable y0 = (-1.0 /ma)*(x0-System.Convert.ToDouble(point1.X+point2.X)/2.0)+System.Convert.ToDouble(point1.Y+point2.Y)/2.0;
               
        let mutable r = sqrt( (System.Convert.ToDouble(point1.X) - x0)*(System.Convert.ToDouble(point1.X) - x0) + (System.Convert.ToDouble(point1.Y) - y0) *(System.Convert.ToDouble(point1.Y) - y0) );
        for angle in 0 .. 360 do
            let x1 = x0 + sin(3.14159265 * System.Convert.ToDouble(angle)/180.0) * r;
            let y1 = y0 + cos(3.14159265 * System.Convert.ToDouble(angle)/180.0) * r;
            this.AddPoint(new Point(System.Convert.ToInt32(x1),System.Convert.ToInt32(y1))); 
    
    member this.doCircle2() =
        //this.Points <- seq [];

        let mutable point1 = p1;
        let mutable point2 = p2;
        let mutable point3 = p3;
        
        let mutable l1 = sqrt( (System.Convert.ToDouble(point3.X- point2.X))*(System.Convert.ToDouble(point3.X- point2.X)) + (System.Convert.ToDouble(point3.Y- point2.Y)) *(System.Convert.ToDouble(point3.Y- point2.Y)) );
        let mutable l2 = sqrt( (System.Convert.ToDouble(point3.X- point1.X))*(System.Convert.ToDouble(point3.X- point1.X)) + (System.Convert.ToDouble(point3.Y- point1.Y)) *(System.Convert.ToDouble(point3.Y- point1.Y)) );
        let mutable l3 = sqrt( (System.Convert.ToDouble(point1.X- point2.X))*(System.Convert.ToDouble(point1.X- point2.X)) + (System.Convert.ToDouble(point1.Y- point2.Y)) *(System.Convert.ToDouble(point1.Y- point2.Y)) );
        
        let mutable x0 = ( l1 * System.Convert.ToDouble(point1.X) + l2 * System.Convert.ToDouble(point2.X) + l3 * System.Convert.ToDouble(point3.X) ) / (l1 + l2 + l3);
        let mutable y0 = ( l1 * System.Convert.ToDouble(point1.Y) + l2 * System.Convert.ToDouble(point2.Y) + l3 * System.Convert.ToDouble(point3.Y) ) / (l1 + l2 + l3);
        let mutable p = ( l1 + l2 + l3 ) / 2.0;
               
        let mutable r = sqrt( (p - l1)*(p - l3)*(p - l2)/p);
        for angle in 0 .. 360 do
            let x1 = x0 + sin(3.14159265 * System.Convert.ToDouble(angle)/180.0) * r;
            let y1 = y0 + cos(3.14159265 * System.Convert.ToDouble(angle)/180.0) * r;
            this.AddPoint(new Point(System.Convert.ToInt32(x1),System.Convert.ToInt32(y1)));                    
        
    member this.checkTriangle() = 
        this.findTopPoints();

        let mutable count = 4;
        if Point.AbsoluteEq(leftP, topP)
        then 
            count <- count - 1;
        if Point.AbsoluteEq(rightP, topP)
        then 
            count <- count - 1;
        if Point.AbsoluteEq(leftP, bottomP)
        then 
            count <- count - 1;
        if Point.AbsoluteEq(rightP, bottomP)
        then 
            count <- count - 1;
        if topP.Y > bottomP.Y
        then 
            count <- count - 4;

        let mutable figure = new Figure();

        if count = 3
        then
            let function1(pon1:Point,pon2:Point, figure:Figure) =
                let mutable deltaX = pon2.X - pon1.X;
                if deltaX < 0
                then deltaX <- deltaX - 1;
                else deltaX <- deltaX + 1;
                
                let mutable deltaY = pon2.Y - pon1.Y;
                if deltaY < 0
                then deltaY <- deltaY - 1;
                else deltaY <- deltaY + 1;


                if abs(abs(deltaX) + abs(deltaY)) > 6
                then
                    let mutable stepX = System.Convert.ToDouble(deltaX)/System.Convert.ToDouble(abs(deltaY));
                    let mutable stepY = System.Convert.ToDouble(deltaY)/System.Convert.ToDouble(abs(deltaX));
                
                    if abs(stepX) < 1.0
                    then 
                        if stepX < 0.0
                        then stepX <- -1.0;
                        else stepX <- 1.0;
                    if abs(stepY) < 1.0
                    then 
                        if stepY > 0.0
                        then stepY <- 1.0;
                        else stepY <- -1.0;

                    let mutable curStepX = 0.0;
                    let mutable curY = 0; 
                              
                    for x in pon1.X .. pon2.X do                    
                        figure.AddPoint(new Point(x, pon1.Y + curY)); 
                        curStepX <- curStepX + 1.0;
                        if curStepX >= abs(stepX)
                        then
                            curStepX <- curStepX - abs(stepX);
                            curY <- curY + System.Convert.ToInt32(stepY);   
                    
                    let mutable curStepY = 0.0;
                    let mutable curX = 0; 

                    for y in pon1.Y .. pon2.Y do
                        figure.AddPoint(new Point(pon1.X + curX, y)); 
                        curStepY <- curStepY + 1.0;
                        if curStepY >= abs(stepY)
                        then
                            curStepY <- curStepY - abs(stepY);
                            curX <- curX + System.Convert.ToInt32(stepX);
                    for x in pon2.X .. pon1.X do                    
                        figure.AddPoint(new Point(x, pon2.Y + curY)); 
                        curStepX <- curStepX + 1.0;
                        if curStepX >= abs(stepX)
                        then
                            curStepX <- curStepX - abs(stepX);
                            curY <- curY - System.Convert.ToInt32(stepY);   
                    
                    let mutable curStepY = 0.0;
                    let mutable curX = 0; 

                    for y in pon2.Y .. pon1.Y do
                        figure.AddPoint(new Point(pon2.X + curX, y)); 
                        curStepY <- curStepY + 1.0;
                        if curStepY >= abs(stepY)
                        then
                            curStepY <- curStepY - abs(stepY);
                            curX <- curX - System.Convert.ToInt32(stepX);
                    
            function1(p1, p2, figure);  
            function1(p1, p3, figure);  
            function1(p2, p3, figure);  


        let figureP = ref figure;
        let isTr = ref 1;        
        Seq.iteri(fun y c ->  
                if not ( figureP.contents.CheckRelationship c )
                then 
                    isTr := 0
            ) this.Points;
            
        if not (count = 3)
        then
            isTr := 0;
        !isTr = 1
            